In [ ]:
# NOTE Edit config.py to get num_recs=None, else you'll be restricted to ≤200 recs/sp
#   - Want: countries_k='na', com_names_k='us', num_recs=None,
#   - Not:  countries_k='na', com_names_k='us', num_recs=200,
In [ ]:
from notebooks import *
sg.init(None)  # Computes search_recs, if cache miss
In [ ]:
search_recs = sg.search_recs
In [ ]:
# Utils

def _recs_show(
    df,
    scale=None,
    order=[
        'xc_id', 'spectro_disp',
        'species', 'subspecies',
        'year', 'month_day', 'time',
        'type',
        'state', 'elevation', 'lat', 'lng', 'place',
        'remarks',
        'quality', 'recordist', 'background_species', 'date',
    ],
    drop=['license', 'bird_seen', 'playback_used'],
    astype={'year': int},
    replace={'subspecies': {'': '—'}},
    **kwargs,
):
    return (df
        # Drop any indexes (e.g. from filter/sort)
        .reset_index(drop=True)
        # Featurize
        .pipe(recs_featurize_spectro_disp, scale=scale)
        # View
        .pipe(recs_view_cols, append=order)  # append= to ensure all requested cols are included
        .pipe(df_reorder_cols, last=order)  # last= so that unknown cols show up loudly in the front
        .drop(columns=drop)
        .astype(astype)
        .replace(replace)
    )

# XXX Very slow to run over all 45k recs, do lazily instead
# recs = (search_recs
#     .pipe(df_inspect, lambda df: (df.shape,))
#     .pipe(_recs_show)
#     .pipe(df_inspect, lambda df: (df.shape,))
# )

In [ ]:
# Copy selected audio/spectro files to talk dir
for sp, xc_id, desc in [
    ('WREN', 90158, 'male-and-female'),
    ('PSFL', 348155, 'dawn-song'),
    ('PSFL', 348142, 'song'),
]:
    payload_id      = 'search_recs-audio_s(10),version(8),com_names_k(us),countries_k(na),num_recs(200)-4a07700'
    search_recs_dir = 'data/cache/payloads/%(payload_id)s/mobile-version(2)/search_recs' % locals()
    talk_dir        = os.path.expanduser('~/Desktop/mb-talk-data')
    shell(**locals(), cmd='''
        cp -v %(search_recs_dir)s/audio/%(sp)s/audio-%(sp)s-%(xc_id)s.mp4     %(talk_dir)s/%(sp)s-%(xc_id)s-%(desc)s.mp4
        cp -v %(search_recs_dir)s/spectro/%(sp)s/spectro-%(sp)s-%(xc_id)s.png %(talk_dir)s/%(sp)s-%(xc_id)s-%(desc)s.png
    ''')

By gender

  • WREN
  • (More: GHOW, RWBL?)
In [ ]:
# WREN
#   - [Pie19] p365
#       - Male song, female song, duet [verify]
#       - [PFGBS] https://academy.allaboutbirds.org/peterson-field-guide-to-bird-sounds/?speciesCode=wrenti
#   - [BNA] https://birdsna.org/Species-Account/bna/species/wrenti/sounds
#       - "A long (2–5 s) series of short, clear, overslurred whistles at about 4 kHz, accelerating into a rapid
#         chatter."
#       - "Female song is similar, but with an even rhythm, and with a highly variable number of notes (3–14)."
#       - "Number of introductory notes is variable, but typically 3–5 in the male song, and the quality of those notes
#         can vary with increasing agitation."
#       - "Partial male songs are common and sound identical to female songs."
#   - Recs
#       - WREN/90158 male and female (duet)
(search_recs
    .pipe(df_inspect, lambda df: (df.shape,))
    # Filter
    [lambda df: reduce(lambda x, y: x & y, [
        df.species == 'WREN',
        # df.remarks.str.lower().str.contains('female'),  # Not useful
        # df.remarks.str.lower().str.contains('slow'),  # Not useful
        # df.remarks.str.lower().str.contains('male'),  # Not useful
        df.xc_id.isin([90158]),
    ])]
    .pipe(df_inspect, lambda df: (df.shape,))
    # Sort
    .sort_values('date', ascending=False)
    # View
    .pipe(_recs_show,
        scale=3,
    )
    [:500]
)
(52613, 71)
(1, 71)
Out[ ]:
xc_id spectro_disp species subspecies year month_day time type state elevation lat lng place remarks quality recordist background_species date
0
90158
WREN
1999
03-29
?
song
California, United States
40 m
35.3
-121.0
Coon Creek Trail, Montana de Oro State Park, California, United States
Two males and a female or juvenile?
A
Thomas G. Graves
[]
1999-03-29 00:00:00

By age

In [ ]:
# RTHA
#   - [Pie19] p205
#       - Squeal: "Given by immature birds in their first summer and fall... May transition gradually into adult Scream
#         over course of first fall and winter; more study needed."
#   - Recs
#       - RTHA/187482 - squeal (juv) - clean
#       - RTHA/139200 - squeal (juv) - messy
#       - RTHA/65409  - scream (adult) - clean
#       - RTHA/173877 - transitional squeal/scream [good]
#       - RTHA/173880 - transitional squeal/scream [good, but too quiet]
(search_recs
    .pipe(df_inspect, lambda df: (df.shape,))
    # Filter
    [lambda df: reduce(lambda x, y: x & y, [
        df.species == 'RTHA',
        df.xc_id.isin([187482, 139200, 65409, 173877, 173880]),
    ])]
    .pipe(df_inspect, lambda df: (df.shape,))
    # Sort
    # .sample(frac=1, random_state=0)
    # [lambda df: ~df.subspecies.isin([''])].sort_values(['subspecies'], ascending=[True])
    # .sort_values('month_day')
    # View
    .pipe(_recs_show,
        scale=3,
    )
    # [:100]
)
(52613, 71)
(5, 71)
Out[ ]:
xc_id spectro_disp species subspecies year month_day time type state elevation lat lng place remarks quality recordist background_species date
0
173877
RTHA
2012
06-20
09:35
flight call
Florida, United States
20 m
27.9
-81.2
Joe Overstreet Rd, Lake Kissimmee, Osceola County, Florida, United States
B
Paul Marvin
['EAME', 'NOBO', 'COYE']
2012-06-20 00:00:00
1
173880
RTHA
2012
10-28
13:29
call
California, United States
10 m
32.6
-117.0
Dairymart Ponds, San Diego County, California, United States
on telephone pole
B
Paul Marvin
[]
2012-10-28 00:00:00
2
65409
RTHA
calurus
2010
06-14
07:45
keer call
California, United States
1520 m
39.7
-120.0
Carman Valley, Sierra County, California, United States
bird calling while perched atop tall conifer. also can hear Douglas's squirrel twittering
A
Eric DeFonso
['MODO', 'AMRO']
2010-06-14 00:00:00
3
187482
RTHA
2014
07-16
10:30
call, juvenile
British Columbia, Canada
90 m
48.5
-123.0
Hector Rd, Vancouver Island, British Columbia, Canada
Whistles from recently-fledged juvenile, given in flight.
no score
Ian Cruickshank
[]
2014-07-16 00:00:00
4
139200
RTHA
borealis
2013
06-18
16:30
call, juvenile
Georgia, United States
3 m
31.9
-81.1
Savannah, Chatham, Georgia, United States
Amplification was boosted. The original recording was shortened to exclude nearby construction noise. The intervals between the calls are as recorded. The two fledglings were following a parent ...
A
Russ Wigh
['BTGR']
2013-06-18 00:00:00

By time of day

In [ ]:
# PSFL: dawn song vs. normal song
#   - [Pie19] p272
#       - Dawn song, normal song
#       - (No "dawn" at [PFGBS] https://academy.allaboutbirds.org/peterson-field-guide-to-bird-sounds/?speciesCode=pasfly)
#   - [BNA] https://birdsna.org/Species-Account/bna/species/pasfly/sounds
#       - Same as [Pie19]
#   - Recs
#       - PSFL/348155 dawn song
#       - PSFL/348142 song
(search_recs
    .pipe(df_inspect, lambda df: (df.shape,))
    # Filter
    [lambda df: reduce(lambda x, y: x & y, [
        df.species == 'PSFL',
        df.recordist.str.lower().str.match(r'.*webster.*'),
        df.xc_id.isin([348155, 348142]),
    ])]
    .pipe(df_inspect, lambda df: (df.shape,))
    # Sort
    # .sort_values(['subspecies', 'lat'], ascending=[True, False])
    # .sort_values(['lat'], ascending=False)
    # .sort_values(['lng'], ascending=True)
    .sort_values(['time'], ascending=True)
    # View
    .pipe(_recs_show,
        scale=3,
    )
    [:500]
)
(52613, 71)
(2, 71)
Out[ ]:
xc_id spectro_disp species subspecies year month_day time type state elevation lat lng place remarks quality recordist background_species date
0
348155
PSFL
cineritius
2001
06-15
05:20
dawn song
Baja California, Mexico
2300 m
31.0
-116.0
La Corona Arriba, Sierra San Pedro Martir, Baja California, Mexico
territory No 1, 3rd recording; some interaction type notes toward the end
B
Richard E. Webster
['MOCH', 'ACWO']
2001-06-15 00:00:00
1
348142
PSFL
cineritius
2001
06-15
05:25
male position note
Baja California, Mexico
2300 m
31.0
-116.0
La Corona Arriba, Sierra San Pedro Martir, Baja California, Mexico
territory No 1 recorded here, 4th recording; male position note
A
Richard E. Webster
['MOCH', 'DEJU', 'WBNU', 'PYNU']
2001-06-15 00:00:00

Within one individual

In [ ]:
# HUVI
#   - [Pie19] p297
#       - "Phrases vary tremendously"
#       - "Incessant repetition of the same sound can be an excellent field mark, but singing occasionally deviates from
#         this pattern"
#   - [BNA] https://birdsna.org/Species-Account/bna/species/hutvir/sounds
#       - "Much individual and geographic variation"
#       - "Typical song pattern is a monotonous and unmusical series of nasal and wheezy 2-syllable, ascending phrases
#         ... repeated approximately 1 per second for a period sometimes spanning ≥ 10 min"
#       - "A common variation is composed of descending phrases"
#       - "A bird may sing either form, may alternate between the 2 forms, and occasionally may mix ascending and
#         descending phrases in the same series ... producing a pattern reminiscent of the song of Cassin's Vireo"
(search_recs
    .pipe(df_inspect, lambda df: (df.shape,))
    # Filter
    [lambda df: reduce(lambda x, y: x & y, [
        df.species == 'HUVI',
    ])]
    .pipe(df_inspect, lambda df: (df.shape,))
    # Sort
    .sample(frac=1, random_state=2)
    # View
    .pipe(_recs_show,
        scale=3,
    )
    [:25]
)
(52613, 71)
(179, 71)
Out[ ]:
xc_id spectro_disp species subspecies year month_day time type state elevation lat lng place remarks quality recordist background_species date
0
402932
HUVI
2018
02-14
08:19
call
Arizona, United States
1800 m
32.4
-111.0
Cypress Picnic Area, Mount Lemmon, Pima County, Arizona, United States
Hutton's vireo calls recorded at a range of roughly 40 - 50 meters on a north-facing slope with Chihuahua pine, ponderosa pine, alligator juniper, and oaks. Distant roar from a plane is audible....
no score
Lance A. M. Benner
['ACWO']
2018-02-14 00:00:00
1
412615
HUVI
2018
04-08
16:42
call
Cerro Alto Campground, United States
340 m
35.4
-121.0
Atascadero, California, Cerro Alto Campground, United States
B
Thomas G. Graves
['STJA']
2018-04-08 00:00:00
2
92953
HUVI
2008
04-30
08:55
song
TX, United States
1900 m
30.7
-104.0
N side Mt Livermore, Davis Mts, TX, United States
Natural song (or response to pishing?) from a bird about 3-4m up in Pinyon Pine amid Ponderosa and madrone/oak parkland.
B
Daniel Lane
['WWDO', 'BEWR']
2008-04-30 00:00:00
3
156192
HUVI
2011
06-10
15:00
song
British Columbia, Canada
420 m
48.5
-124.0
Crabapple Lake, Sooke Hills, Vancouver Island, British Columbia, Canada
A
Ian Cruickshank
['AMRO', 'TOWA']
2011-06-10 00:00:00
4
183585
HUVI
2014
06-24
07:00
song
British Columbia, Canada
80 m
48.5
-123.0
Saanich (near Victoria), Capital, British Columbia, Canada
somewhat atypical song (fast phrasing).
B
Ian Cruickshank
[]
2014-06-24 00:00:00
5
405621
HUVI
2018
03-11
14:05
song
California, United States
1300 m
34.2
-118.0
Glendora Ridge Road mile 10.4, San Gabriel Mountains, Los Angeles County, California, United States
Recorded at a range of about 70 meters on a forested, north-facing slope. Equipment: Sony PCM-M10 recorder, Sennheiser ME62 microphone, and a Telinga 22 inch parabola. Edits: trimmed and normalize...
no score
Lance A. M. Benner
['OATI']
2018-03-11 00:00:00
6
232139
HUVI
2001
03-11
12:00
call?
Oaxaca, Mexico
2600 - 2800 m
17.2
-96.6
Cerro San Felipe (La Cumbre), Oaxaca, Mexico
ID certainty 90%. (Archiv. tape 121 side B track 19 seq. A)
B
Peter Boesman
[]
2001-03-11 00:00:00
7
30595
HUVI
stephensi
2009
02-15
09:00
song
New Mexico, United States
? m
31.4
-109.0
Guadalupe Canyon, Hidalgo Co., New Mexico, United States
A
Andrew Spencer
[]
2009-02-15 00:00:00
8
323414
HUVI
stephensi
2015
05-31
11:15
song
Chiricahua Mountains, United States
1700 m
31.8
-109.0
Rucker Canyon, Chiricahua Mountains, United States
in response to pygmy-owl fuss disturbance; Individual No 2, 2nd recording today
B
Richard E. Webster
['BUSH', 'DCFL', 'BRTI']
2015-05-31 00:00:00
9
125471
HUVI
2013
03-17
09:25
song
Cerro Alto Campground, United States
320 m
35.4
-121.0
Atascadero, California, Cerro Alto Campground, United States
Hutton's Vireo again? with a little burr in it's voice? A pair singing.
A
Thomas G. Graves
[]
2013-03-17 00:00:00
10
296985
HUVI
2011
06-22
10:56
song
Texas, United States
2000 m
29.3
-103.0
Laguna Meadows Trail, Big Bend National Park, Brewster Co., Texas, United States
B
Paul Marvin
['SCOR']
2011-06-22 00:00:00
11
282857
HUVI
2015
03-04
16:30
male, song
Arizona, United States
1000 m
33.9
-111.0
Bushnell Tanks, Sunflower, Maricopa County, Arizona, United States
Amplification, low and high pass filters used in Audacity.
A
Eric Hough
['DEJU', 'BUSH']
2015-03-04 00:00:00
12
252186
HUVI
2015
06-10
08:30
song
Mex DF entrance Desierto de los Leones, Mexico
2900 m
19.3
-99.3
Mex DF entrance Desierto de los Leones, Mexico
B
Manuel Grosselet
[]
2015-06-10 00:00:00
13
413985
HUVI
2018
05-06
08:00
call
British Columbia, Canada
110 m
48.6
-123.0
Newton Heights, Victoria, British Columbia, Canada
Very quiet calls made while foraging, after one song note. These calls used the same rhythm as a typical song (though a little faster), and were almost inaudible (bird was only about 2m away from m...
C
Randy Dzenkiw
[]
2018-05-06 00:00:00
14
365405
HUVI
mexicanus
2017
03-25
07:00
call
Michoacán, Mexico
2000 m
19.5
-102.0
Uruapan, Michoacán, Mexico
Bosque de pino-encino. Ruido por gallo doméstico, audio amplificado 25dB y filtrado High pass.
no score
Juan Carlos Pérez M.
[]
2017-03-25 00:00:00
15
297611
HUVI
2012
07-25
08:44
song
Arizona, United States
1800 m
31.7
-111.0
Super Trail, Madera Canyon, Continental, Arizona, United States
A
Paul Marvin
['GRPE', 'WBNU', 'PLVI']
2012-07-25 00:00:00
16
212822
HUVI
oberholseri
2015
02-07
15:30
call
California, United States
10 m
32.6
-117.0
Tijuana River Valley Regional Park, San Diego County, California, United States
Riparian habitat in arid region near the coast.
C
Nick Komar
[]
2015-02-07 00:00:00
17
282597
HUVI
stephensi
2015
08-14
08:30
call, song
Sonora, Mexico
2100 m
28.4
-109.0
Mesa del Campanero, Sonora, Mexico
High pass filter ran and amplified. In an area of mixed Pine-oak with a lot of Arbutus sp with a Arctostaphylos sp. dominated understory. Came in to spishing and pygmy owl whistling. Part of a lo...
B
David Vander Pluym
[]
2015-08-14 00:00:00
18
105702
HUVI
cognatus
2008
07-15
1100
excited song
Baja California Sur, Mexico
1900 m
23.5
-110.0
Sierra La Laguna Biosphere Reserve, Baja California Sur, Mexico
Solo bird, not one of the two from XC105701
B
Nathan Pieplow
['ACWO', 'SPTO', 'YEJU', 'PSFL', 'WWDO', 'BGGN']
2008-07-15 00:00:00
19
256398
HUVI
2014
03-28
?
song
Arizona, United States
140 m
34.3
-114.0
Bill Williams River NWR, Arizona, United States
Documentation for rare but increasing species in this area.
C
Lauren Harter
[]
2014-03-28 00:00:00
20
358938
HUVI
2017
03-06
12:00
call
Texas, United States
340 m
29.6
-98.6
Texas (near San Antonio), Bexar County, Texas, United States
one of several calling birds in a close area. volume maximized and cleaned up with a 300 hz highpass filter
B
David Sarkozi
[]
2017-03-06 00:00:00
21
168038
HUVI
2014
02-23
08:00
call
Mex DF entrance Desierto de los Leones, Mexico
2900 m
19.3
-99.3
Mex DF entrance Desierto de los Leones, Mexico
perched and moving in the tree, calling.
A
Manuel Grosselet
['BBSO', 'VGSW', 'GRSF']
2014-02-23 00:00:00
22
324079
HUVI
2015
05-01
09:29
song
Arizona, United States
1600 m
31.9
-109.0
South Fork Road, Portal, Arizona, United States
B
Paul Marvin
[]
2015-05-01 00:00:00
23
73497
HUVI
2011
03-15
08:30
Song
British Columbia, Canada
40 m
48.5
-123.0
Mount Douglas Park, Victoria, British Columbia, Canada
A
Ian Cruickshank
[]
2011-03-15 00:00:00
24
283520
HUVI
stephensi
2015
08-14
12:05
song
Sonora, Mexico
2100 m
28.4
-109.0
Mesa del Campanero, Sonora, Mexico
High pass filter ran and amplified. North edge of mesa, but on top, mixed pine and oak with somewhat open understory, though some patches of denser brush and shorter trees. Had been singing for a w...
B
David Vander Pluym
[]
2015-08-14 00:00:00

By time of year (season)

  • Omitted: not worthwhile given the ones we already have above
    • YRWA - visually similar to WIWA, doesn't add much
    • HETH - takes a moment to see
    • RCKI - hard to visually parse
In [ ]:
def _show_seasonal(
    species,
    filters=lambda df: [],
    bins=2,  # 2 | 4
    n=None,
    scale=None,
    scale_base=3.8,
    random_state=0,
):
    assert bins in [2, 4]
    if n is None:
        n = 50 // bins
    return (search_recs
        .pipe(df_inspect, lambda df: (df.shape,))
        # Filter
        [lambda df: reduce(lambda x, y: x & y, [
            df.species == species,
            *filters(df),
        ])]
        .pipe(df_inspect, lambda df: (df.shape,))
        # Sort
        # .sample(100, random_state=random_state)
        .sort_values(['month_day'], ascending=[False])
        # View
        .pipe(_recs_show,
            scale=scale or scale_base / bins,
        )
        [:1000]  # Safeguard: trim to a reasonable max (> any sp, but << all recs)
        # Bin by season (4 bins)
        #   - Boundaries based roughly on https://birdsna.org/Species-Account/bna/species/ruckin/breeding
        .assign(season=lambda df: df.month_day.str.split('-').str[0].map(lambda x: {
            '09': 'fall migration',
            '10': 'fall migration',
            '11': 'fall migration',
            '12': 'winter',
            '01': 'winter',
            '02': 'winter',
            '03': 'spring migration',
            '04': 'spring migration',
            '05': 'spring migration',
            '06': 'breeding',
            '07': 'breeding',
            '08': 'breeding',
        }.get(x)))
        .assign(season=lambda df: df.season.pipe(lambda s: s.pipe(as_ordered_cat, [
            'fall migration', 'winter', 'spring migration', 'breeding',
        ])))
        # Bin further
        #   - For bigger spectros (4->2 cols)
        .pipe(lambda df: df if bins == 4 else (df
            .replace({'season': {
                'spring migration': 'spring migration / breeding',
                'breeding':         'spring migration / breeding',
                'fall migration':   'fall migration / winter',
                'winter':           'fall migration / winter',
            }})
            .assign(season=lambda df: df.season.pipe(lambda s: s.pipe(as_ordered_cat, [
                'fall migration / winter', 'spring migration / breeding',
            ])))
        ))
        # Pivot by season (manually)
        .pipe(lambda df: pd.concat(axis=1, objs=[
            (df
                [df.season == season]
                [['spectro_disp']]
                .rename(columns={'spectro_disp': season})
                .sample(frac=1, random_state=random_state)  # Randomize per column (to avoid weird biases from incidental sorting above)
                .reset_index(drop=True)
            )
            for season in df.season.sort_values().unique()
        ]))
        .fillna('')
        .pipe(df_inspect, lambda df: (df.shape,))
        [:n]
        .pipe(df_inspect, lambda df: (df.shape,))
    )
In [ ]:
# Good: visually apparent
_show_seasonal('WIWA')
(52613, 71)
(204, 71)
(180, 2)
(25, 2)
Out[ ]:
fall migration / winter spring migration / breeding
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
In [ ]:
# Good
#   - Take a moment to explain wraa calls on the left vs. trill songs on the right
_show_seasonal('SPTO')
(52613, 71)
(521, 71)
(429, 2)
(25, 2)
Out[ ]:
fall migration / winter spring migration / breeding
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
In [ ]:
# Good
#   - Take a moment to explain chips on the left vs. songs on the right
show_seasonal('FOSP')
(52613, 71)
(501, 71)
(391, 2)
(25, 2)
Out[ ]:
fall migration / winter spring migration / breeding
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
In [ ]:
# [Skippable]
# Good example of partial switch
#   - [Pie19] "All year, but mostly Mar—Aug"
_show_seasonal('SOSP')
(52613, 71)
(648, 71)
(498, 2)
(25, 2)
Out[ ]:
fall migration / winter spring migration / breeding
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

By subspecies (/ geography)

In [ ]:
def _show_seasonal(
    species,
    filters=lambda df: [],
    bins=2,  # 2 | 4
    n=None,
    scale=None,
    scale_base=3.8,
    random_state=0,
):
    assert bins in [2, 4]
    if n is None:
        n = 50 // bins
    return (search_recs
        .pipe(df_inspect, lambda df: (df.shape,))
        # Filter
        [lambda df: reduce(lambda x, y: x & y, [
            df.species == species,
            *filters(df),
        ])]
        .pipe(df_inspect, lambda df: (df.shape,))
        # Sort
        # .sample(100, random_state=random_state)
        .sort_values(['month_day'], ascending=[False])
        # View
        .pipe(_recs_show,
            scale=scale or scale_base / bins,
        )
        [:1000]  # Safeguard: trim to a reasonable max (> any sp, but << all recs)
        # Bin by season (4 bins)
        #   - Boundaries based roughly on https://birdsna.org/Species-Account/bna/species/ruckin/breeding
        .assign(season=lambda df: df.month_day.str.split('-').str[0].map(lambda x: {
            '09': 'fall migration',
            '10': 'fall migration',
            '11': 'fall migration',
            '12': 'winter',
            '01': 'winter',
            '02': 'winter',
            '03': 'spring migration',
            '04': 'spring migration',
            '05': 'spring migration',
            '06': 'breeding',
            '07': 'breeding',
            '08': 'breeding',
        }.get(x)))
        .assign(season=lambda df: df.season.pipe(lambda s: s.pipe(as_ordered_cat, [
            'fall migration', 'winter', 'spring migration', 'breeding',
        ])))
        # Bin further
        #   - For bigger spectros (4->2 cols)
        .pipe(lambda df: df if bins == 4 else (df
            .replace({'season': {
                'spring migration': 'spring migration / breeding',
                'breeding':         'spring migration / breeding',
                'fall migration':   'fall migration / winter',
                'winter':           'fall migration / winter',
            }})
            .assign(season=lambda df: df.season.pipe(lambda s: s.pipe(as_ordered_cat, [
                'fall migration / winter', 'spring migration / breeding',
            ])))
        ))
        # Pivot by season (manually)
        .pipe(lambda df: pd.concat(axis=1, objs=[
            (df
                [df.season == season]
                [['spectro_disp']]
                .rename(columns={'spectro_disp': season})
                .sample(frac=1, random_state=random_state)  # Randomize per column (to avoid weird biases from incidental sorting above)
                .reset_index(drop=True)
            )
            for season in df.season.sort_values().unique()
        ]))
        .fillna('')
        .pipe(df_inspect, lambda df: (df.shape,))
        [:n]
        .pipe(df_inspect, lambda df: (df.shape,))
    )
In [ ]:
# SPTO
#   - [Pie19] p425
#       - "Typical version: 2 unmusical series or trills, second higher"
#       - "West Coast version: single long buzz"
#   - [BNA] https://birdsna.org/Species-Account/bna/species/spotow/sounds
#       - "Interior males sing songs generally containing both introductory and trill phrases, while coastal birds usually
#         sing only trills."
#       - Far western (coastal) birds trill faster on average than interior (mountain, plains) western birds, but trill
#         rates are variable and largely overlapping (15.4–32.3 syll/s vs. 14.5–21.3 syll/s)
#   - [BNA] https://birdsna.org/Species-Account/bna/species/spotow/systematics
#       - 21 subsp (see map)
#       - Various isolated subsp in the southern end of range (MX)
(search_recs
    .pipe(df_inspect, lambda df: (df.shape,))
    # Filter
    [lambda df: reduce(lambda x, y: x & y, [
        df.species == 'SPTO',
        # df.type.str.lower().str.match(r'.*song.*'),
        # df.type.str.lower().str.match(r'^song$'),
        df.quality.isin(['A', 'B']),
    ])]
    .pipe(df_inspect, lambda df: (df.shape,))
    # Sort
    # .sample(250, random_state=0)
    # .sample(50, random_state=0)
    # .sort_values(['subspecies', 'lat'], ascending=False)
    # .sort_values(['lat'], ascending=False)
    # .sort_values(['lng'], ascending=True)
    .pipe(df_inspect, lambda df: (df.shape,))
    # View
    .pipe(_recs_show,
        scale=1.9,
    )

    # Bin by geo (2 bins)
    #   - Very rough, but decent results

    # .assign(geo=lambda df: df.state.str.lower().str.replace('.', '').str.split(r',\s*').map(lambda states: first(
    #     [
    #         geo
    #         for state in states
    #         for geo in [{
    #
    #             # # 'british columbia': 'west coast',
    #             # # 'bc':               'west coast',
    #             # # 'washington':       'west coast',
    #             # # 'wa':               'west coast',
    #             # # 'oregon':           'west coast',
    #             # 'california':       'west coast',
    #             # 'ca':               'west coast',
    #             # # 'inyo county':      'interior',  # Right? (Inyo County ~ Death Valley, CA)
    #             # # 'colorado':         'interior',
    #             # # 'utah':             'interior',
    #             # 'arizona':          'interior',
    #             # 'az':               'interior',
    #             # 'new mexico':       'interior',
    #             # # 'mexico':           'interior',
    #
    #             # 'british columbia': 'west coast',
    #             # 'bc':               'west coast',
    #             # 'washington':       'west coast',
    #             # 'wa':               'west coast',
    #             # 'oregon':           'west coast',
    #             'california':       'california',
    #             'ca':               'california',
    #             # 'inyo county':      'interior',  # Right? (Inyo County ~ Death Valley, CA)
    #             'colorado':         'colorado',
    #             # 'utah':             'interior',
    #             # 'arizona':          'arizona',
    #             # 'az':               'arizona',
    #             # # 'new mexico':       'new mexico',
    #             # 'mexico':           'mexico',
    #
    #         }.get(state)]
    #         if geo is not None
    #     ] + [
    #         None,
    #     ]
    # )))

    .assign(geo=lambda df: df.pipe(df_map_rows, lambda row: (
        'W -117 (coastal CA)' if row.lng < -117 else  # -117 to exclude Inyo County (Death Valley) which behaves ~like interior
        'E -110 (CO/AZ/MX)'   if row.lng > -110 else  # -110 to include CO/AZ/MX (at least)
        None                                          # Throw out everything in the middle, to simplify analysis
    )))

    [lambda df: df.geo.notnull()]
    .assign(geo=lambda df: df.geo.pipe(lambda s: s.pipe(as_ordered_cat, [
        # 'west coast', 'interior',
        # 'california', 'colorado', 'arizona', 'mexico',
        # 'california', 'colorado',
        'W -117 (coastal CA)', 'E -110 (CO/AZ/MX)',
    ])))
    # .pipe(df_inspect, lambda df: df[:250])  # Debug

    # Pivot by geo (manually)
    .pipe(lambda df: pd.concat(axis=1, objs=[
        (df
            [df.geo == geo]
            [['spectro_disp']]
            .rename(columns={'spectro_disp': geo})
            .sample(frac=1, random_state=0)  # Randomize per column (to avoid weird biases from incidental sorting above)
            .reset_index(drop=True)
        )
        for geo in df.geo.sort_values().unique()
    ]))
    .fillna('')
    .pipe(df_inspect, lambda df: (df.shape,))
    [:25]
    .pipe(df_inspect, lambda df: (df.shape,))

)
(52613, 71)
(432, 71)
(432, 71)
(230, 2)
(25, 2)
Out[ ]:
W -117 (coastal CA) E -110 (CO/AZ/MX)
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

Final quiz

  • (All the damn wraa calls)
In [ ]:
# To search for examples
# (search_recs
#     .pipe(df_inspect, lambda df: (df.shape,))
#     # Filter
#     [lambda df: reduce(lambda x, y: x & y, [
#         df.species == 'GGSH',
#     ])]
#     .pipe(df_inspect, lambda df: (df.shape,))
#     # Sort
#     .sample(frac=1, random_state=0)
#     # View
#     .pipe(_recs_show,
#         # scale=3,
#     )
#     [:250]
# )
In [ ]:
(search_recs
    .pipe(df_inspect, lambda df: (df.shape,))
    # Filter
    [lambda df: reduce(lambda x, y: x | y, [

        (df.species == 'SPTO') & df.xc_id.isin([127012]),
        (df.species == 'EATO') & df.xc_id.isin([293823]),

        (df.species == 'HUVI') & df.xc_id.isin([297120]),
        # (df.species == 'HUVI') & df.xc_id.isin([348987]),
        (df.species == 'WAVI') & df.xc_id.isin([159366]),
        # (df.species == 'WAVI') & df.xc_id.isin([381527]),

        (df.species == 'HETH') & df.xc_id.isin([314303]),
        # (df.species == 'HETH') & df.xc_id.isin([131636]),

        (df.species == 'BEWR') & df.xc_id.isin([163209]),
        # (df.species == 'BEWR') & df.xc_id.isin([141349]),
        (df.species == 'HOWR') & df.xc_id.isin([265810]),

        (df.species == 'BANO') & df.xc_id.isin([294969]),  # Juv shriek [PFGBS]
        (df.species == 'GHOW') & df.xc_id.isin([154990]),  # Juv shriek [PFGBS]

        (df.species == 'BGGN') & df.xc_id.isin([376229]),
        # (df.species == 'BGGN') & df.xc_id.isin([81059]),
        (df.species == 'BCGN') & df.xc_id.isin([30087]),
        (df.species == 'BTGN') & df.xc_id.isin([253889]),
        (df.species == 'CAGN') & df.xc_id.isin([17808]),

        (df.species == 'LOSH') & df.xc_id.isin([255158]),
        # (df.species == 'LOSH') & df.xc_id.isin([255145]),
        (df.species == 'GGSH') & df.xc_id.isin([91968]),  # NOSH (Northern Shrike) used to be GGSH (Great Gray Shrike)

        (df.species == 'CASJ') & df.xc_id.isin([347904]),
        (df.species == 'STJA') & df.xc_id.isin([146610]),

    ])]
    .pipe(df_inspect, lambda df: (df.shape,))
    # View
    .pipe(_recs_show,
        scale=2.9,
    )
    .pipe(df_ordered_cats_like, species=metadata.ebird.df.shorthand)
    .sort_values(['species'])
)
(52613, 71)
(17, 71)
Out[ ]:
xc_id spectro_disp species subspecies year month_day time type state elevation lat lng place remarks quality recordist background_species date
4
294969
BANO
2015
06-06
04:30
, begging call, cleaking, juvenile
Washington, United States
100 m
47.7
-122.0
Seattle, King County, Washington, United States
The recording starts with a young juvenile begging (with another juvenile in the background) at :10 an adult and does a food drop at :43 the adult starts vocalizing, eventually both the juvenile an...
A
Bruce Lagerquist
['AMRO', 'KILL']
2015-06-06 00:00:00
1
154990
GHOW
2012
10-22
05:30
call
Pennsylvania, United States
40 m
40.1
-75.1
Lower Moreland (near Huntingdon Valley), Montgomery, Pennsylvania, United States
shrieks and chitter call
A
Paul Driver
[]
2012-10-22 00:00:00
11
255158
LOSH
2014
08-29
10:25
call
Arizona, United States
1100 m
31.3
-109.0
San Bernardino National Wildlife Refuge, Cochise County, Arizona, United States
wintering or migrating bird at this location
A
Richard E. Webster
[]
2014-08-29 00:00:00
10
91968
GGSH
invictus
2011
12-22
09:00
call, song
Washington, United States
550 m
49.0
-119.0
Mary Ann Creek Road, Okanogan Co., Washington, United States
from an adult bird a few minutes after playback. Two different call types and some song in this cut.
A
Andrew Spencer
[]
2011-12-22 00:00:00
5
297120
HUVI
2012
12-09
07:12
call
California, United States
10 m
32.6
-117.0
Bird and Butterfly Garden, Tijuana River Valley Regional Park, San Diego Co, California, United States
A
Paul Marvin
[]
2012-12-09 00:00:00
9
159366
WAVI
2012
08-26
07:44
call
BC, Canada
m
48.5
-123.0
Swan Lake, Victoria, Vancouver Island, BC, Canada
Recorded on a Marantz PMD661 recorder using a Sennheiser ME66 microphone.
B
Ian Cruickshank
[]
2012-08-26 00:00:00
12
146610
STJA
2013
08-24
17:30
call
Arizona, United States
2100 m
35.2
-112.0
Flagstaff, Coconino, Arizona, United States
Natural calls from a bird about 5m up, dislodging cones from a branch and watching them fall to the ground in Ponderosa Pine parkland.
B
Dan Lane
['LEGO', 'PYNU']
2013-08-24 00:00:00
8
347904
CASJ
2016
12-25
17:00
call
California, United States
10 m
38.6
-121.0
American River Parkway (East of Watt), Sacramento, Sacramento County, California, United States
A
Jim Holmes
[]
2016-12-25 00:00:00
3
265810
HOWR
cahooni
2015
05-26
19:00
call
Jalisco, Mexico
2500 m
20.7
-105.0
Cerro La Bufa, San Sebastián del Oeste, Jalisco, Mexico
calls from the other member of the pair from XC265809 (so a presumed female).
A
Andrew Spencer
[]
2015-05-26 00:00:00
15
163209
BEWR
2014
01-04
12:24
alarm call
Little Spokane River Natural Area, United States
700 m
47.8
-118.0
Indian Painted Rocks, Little Spokane River Natural Area, United States
A
Garrett MacDonald
[]
2014-01-04 00:00:00
13
376229
BGGN
2017
06-18
05:12
call
Colorado, United States
1900 m
39.9
-105.0
Colorado (near Boulder), Boulder County, Colorado, United States
A Blue-gray Gnatcatcher going off from a shrub along the Fowler Trail.
A
Ted Floyd
[]
2017-06-18 00:00:00
7
17808
CAGN
2008
01-03
14:30
call
California, United States
30 m
33.6
-118.0
Crystal Cove State Park, Orange County, California, United States
B
Nathan Pieplow
['Homo sapiens']
2008-01-03 00:00:00
0
253889
BTGN
2015
04-20
05:47
song
Arizona, United States
600 m
33.5
-112.0
Mesa, Maricopa County, Arizona, United States
Recorded with Sennheiser ME64 /K6 microphone on a Olympus LS-14 recorder. Bird calling from Palo Verde tree. Bird reacted to its own (previous) call from my recorder speaker when I wanted to chec...
A
Patrick Turgeon
[]
2015-04-20 00:00:00
16
30087
BCGN
2009
02-15
11:40
call
New Mexico, United States
? m
31.4
-109.0
Guadalupe Canyon, Hidalgo Co., New Mexico, United States
calls from a male bird, part of a pair. These calls a bit shorter that the typical call of this species, which I believe indicates some level of agitation. A couple of more typical calls at 26-29s
A
Andrew Spencer
[]
2009-02-15 00:00:00
14
314303
HETH
2016
04-29
19:45
call
Great Pubnico Lake Road, Canada
10 m
43.7
-65.8
Great Pubnico Lake Road, Canada
B
Alix dEntremont
[]
2016-04-29 00:00:00
2
127012
SPTO
megalonyx
2001
05-13
07:10
call
San Diego County, United States
100 m
32.7
-117.0
Sweetwater River, SDNWR, San Diego County, United States
calls of a pair;
B
Richard E. Webster
['CALT', 'COYE', 'YBCH', 'American Yellow Warbler']
2001-05-13 00:00:00
6
293823
EATO
2015
11-23
09:30
call
Alabama, United States
60 m
32.0
-85.1
Eufaula, Barbour County, Alabama, United States
A
Jim Holmes
[]
2015-11-23 00:00:00

XXX Attic

In [ ]:
# BEWR HOWR PAWR
# BGGN
# CATH
# NOMO
# LEGO
# BRCR
# RBNU WBNU PYNU
# OATI CBCH
# HUVI WAVI CAVI
# WEKI
# BLPH SAPH WEWP OSFL ATFL PSFL
# RBSA
# HAWO DOWO NUWO ACWO PIWO NOFL
# RTHA(age) RSHA COHA SSHA AMKE MERL
# COLO
In [ ]:
# WCSP
#   - Around bay area?
(search_recs
    .pipe(df_inspect, lambda df: (df.shape,))
    # Filter
    [lambda df: reduce(lambda x, y: x & y, [
        df.species == 'WCSP',
        df.state.str.lower().str.match(r'.*\b(ca|california)\b.*'),
    ])]
    .pipe(df_inspect, lambda df: (df.shape,))
    # Sort
    .sort_values(['subspecies', 'lat'], ascending=[True, False])
    # .sort_values(['lat'], ascending=False)
    # .sort_values(['lng'], ascending=True)
    # View
    .pipe(_recs_show,
        # scale=3,
    )
    [:500]
)
In [ ]:
# SOSP
#   - Don't know what to do with this one
#   - By subspecies?
(search_recs
    .pipe(df_inspect, lambda df: (df.shape,))
    # Filter
    [lambda df: reduce(lambda x, y: x & y, [
        df.species == 'SOSP',
    ])]
    .pipe(df_inspect, lambda df: (df.shape,))
    # Sort
    [lambda df: ~df.subspecies.isin([''])]
    .sample(100, random_state=0)
    .sort_values(['subspecies'], ascending=[True])
    # View
    .pipe(_recs_show,
        # scale=3,
    )
    [:100]
)
In [ ]:
# BEWR
#   - Don't know what to do with this one
#   - Around US?
#   - Across individuals?
(search_recs
    .pipe(df_inspect, lambda df: (df.shape,))
    # Filter
    [lambda df: reduce(lambda x, y: x & y, [
        df.species == 'BEWR',
    ])]
    .pipe(df_inspect, lambda df: (df.shape,))
    # Sort
    .sample(100, random_state=0)
    .sort_values(['lng'], ascending=[True])
    # View
    .pipe(_recs_show,
        # scale=3,
    )
    [:100]
)

Try python-pptx

In [ ]:
import pptx
path = os.path.expanduser('~/Desktop/Birds.pptx')
prs = pptx.Presentation(path)
In [ ]:
dirs(prs)
Out[ ]:
{
  'core_properties': <pptx.parts.coreprops.CorePropertiesPart object at 0x188438eb8>,
  'element': <Element {http://schemas.openxmlformats.org/presentationml/2006/main}presentation at 0x188415a48>,
  'notes_master': <pptx.slide.NotesMaster object at 0x1886e07c8>,
  'part': <pptx.parts.presentation.PresentationPart object at 0x188438208>,
  'save': <bound method Presentation.save of <pptx.presentation.Presentation object at 0x1074ce5e8>>,
  'slide_height': pptx.util.Emu(6858000),
  'slide_layouts': <pptx.slide.SlideLayouts object at 0x187ea3688>,
  'slide_master': <pptx.slide.SlideMaster object at 0x1886ffe60>,
  'slide_masters': <pptx.slide.SlideMasters object at 0x188719508>,
  'slide_width': pptx.util.Emu(12192000),
  'slides': <pptx.slide.Slides object at 0x18889a6c0>
}
In [ ]:
dirs(prs.slides)
Out[ ]:
{
  'add_slide': <bound method Slides.add_slide of <pptx.slide.Slides object at 0x18889a6c0>>,
  'element': <Element {http://schemas.openxmlformats.org/presentationml/2006/main}sldIdLst at 0x1886f7d68>,
  'get': <bound method Slides.get of <pptx.slide.Slides object at 0x18889a6c0>>,
  'index': <bound method Slides.index of <pptx.slide.Slides object at 0x18889a6c0>>,
  'parent': <pptx.presentation.Presentation object at 0x1074ce5e8>,
  'part': <pptx.parts.presentation.PresentationPart object at 0x188438208>
}
In [ ]:
list(prs.slides)
Out[ ]:
[
  <pptx.slide.Slide object at 0x188e16ea8>,
  <pptx.slide.Slide object at 0x1887029a8>,
  <pptx.slide.Slide object at 0x1092dcf98>,
  <pptx.slide.Slide object at 0x188e16f48>,
  <pptx.slide.Slide object at 0x188e16ef8>,
  <pptx.slide.Slide object at 0x188e16a48>,
  <pptx.slide.Slide object at 0x188e16e58>,
  <pptx.slide.Slide object at 0x188e16138>,
  <pptx.slide.Slide object at 0x188e16c78>,
  <pptx.slide.Slide object at 0x188e16e08>,
  <pptx.slide.Slide object at 0x188e16cc8>,
  <pptx.slide.Slide object at 0x188e16db8>,
  <pptx.slide.Slide object at 0x188e16c28>,
  <pptx.slide.Slide object at 0x188e16b38>,
  <pptx.slide.Slide object at 0x188e16778>
]
In [ ]:
dirs(prs.slides[5])
Out[ ]:
{
  'background': <pptx.slide._Background object at 0x18435f288>,
  'element': <Element {http://schemas.openxmlformats.org/presentationml/2006/main}sld at 0x188710728>,
  'follow_master_background': True,
  'has_notes_slide': True,
  'name': '',
  'notes_slide': <pptx.slide.NotesSlide object at 0x186600318>,
  'part': <pptx.parts.slide.SlidePart object at 0x18872ba20>,
  'placeholders': <pptx.shapes.shapetree.SlidePlaceholders object at 0x18985d4e0>,
  'shapes': <pptx.shapes.shapetree.SlideShapes object at 0x17f51b5e8>,
  'slide_id': 263,
  'slide_layout': <pptx.slide.SlideLayout object at 0x1897736d8>
}
In [ ]:
list(prs.slides[5].shapes)
Out[ ]:
[<pptx.shapes.picture.Picture object at 0x189791588>]
In [ ]:
list(prs.slides[-1].shapes)
Out[ ]:
[
  <pptx.shapes.placeholder.SlidePlaceholder object at 0x189791b38>,
  <pptx.shapes.picture.Picture object at 0x189791ba8>,
  <pptx.shapes.picture.Picture object at 0x18986c5c0>
]
In [ ]:
dir(prs.slides[-1].shapes[0])
Out[ ]:
[
  '__class__',
  '__delattr__',
  '__dict__',
  '__dir__',
  '__doc__',
  '__eq__',
  '__format__',
  '__ge__',
  '__getattribute__',
  '__gt__',
  '__hash__',
  '__init__',
  '__init_subclass__',
  '__le__',
  '__lt__',
  '__module__',
  '__ne__',
  '__new__',
  '__reduce__',
  '__reduce_ex__',
  '__repr__',
  '__setattr__',
  '__sizeof__',
  '__str__',
  '__subclasshook__',
  '__weakref__',
  '_base_placeholder',
  '_effective_value',
  '_element',
  '_inherited_value',
  '_parent',
  '_replace_placeholder_with',
  '_sp',
  'adjustments',
  'auto_shape_type',
  'click_action',
  'element',
  'fill',
  'get_or_add_ln',
  'has_chart',
  'has_table',
  'has_text_frame',
  'height',
  'is_placeholder',
  'left',
  'line',
  'ln',
  'name',
  'part',
  'placeholder_format',
  'rotation',
  'shadow',
  'shape_id',
  'shape_type',
  'text',
  'text_frame',
  'top',
  'width'
]
In [ ]:
prs.slides[-1].shapes[0].text
Out[ ]:
'How to audio+image'
In [ ]:
dir(prs.slides[-1].shapes[1])
Out[ ]:
[
  '__class__',
  '__delattr__',
  '__dict__',
  '__dir__',
  '__doc__',
  '__eq__',
  '__format__',
  '__ge__',
  '__getattribute__',
  '__gt__',
  '__hash__',
  '__init__',
  '__init_subclass__',
  '__le__',
  '__lt__',
  '__module__',
  '__ne__',
  '__new__',
  '__reduce__',
  '__reduce_ex__',
  '__repr__',
  '__setattr__',
  '__sizeof__',
  '__str__',
  '__subclasshook__',
  '__weakref__',
  '_element',
  '_parent',
  '_pic',
  'auto_shape_type',
  'click_action',
  'crop_bottom',
  'crop_left',
  'crop_right',
  'crop_top',
  'element',
  'get_or_add_ln',
  'has_chart',
  'has_table',
  'has_text_frame',
  'height',
  'image',
  'is_placeholder',
  'left',
  'line',
  'ln',
  'name',
  'part',
  'placeholder_format',
  'rotation',
  'shadow',
  'shape_id',
  'shape_type',
  'top',
  'width'
]
In [ ]:
(prs.slides[-1].shapes[1].shape_type, pptx.enum.shapes.MSO_SHAPE_TYPE.PICTURE)
Out[ ]:
(pptx.enum.base.EnumValue(13), pptx.enum.base.EnumValue(13))
In [ ]:
dirs(pptx.enum.shapes.MSO_SHAPE_TYPE)
Out[ ]:
{
  'AUTO_SHAPE': pptx.enum.base.EnumValue(1),
  'CALLOUT': pptx.enum.base.EnumValue(2),
  'CANVAS': pptx.enum.base.EnumValue(20),
  'CHART': pptx.enum.base.EnumValue(3),
  'COMMENT': pptx.enum.base.EnumValue(4),
  'DIAGRAM': pptx.enum.base.EnumValue(21),
  'EMBEDDED_OLE_OBJECT': pptx.enum.base.EnumValue(7),
  'FORM_CONTROL': pptx.enum.base.EnumValue(8),
  'FREEFORM': pptx.enum.base.EnumValue(5),
  'GROUP': pptx.enum.base.EnumValue(6),
  'IGX_GRAPHIC': pptx.enum.base.EnumValue(24),
  'INK': pptx.enum.base.EnumValue(22),
  'INK_COMMENT': pptx.enum.base.EnumValue(23),
  'LINE': pptx.enum.base.EnumValue(9),
  'LINKED_OLE_OBJECT': pptx.enum.base.EnumValue(10),
  'LINKED_PICTURE': pptx.enum.base.EnumValue(11),
  'MEDIA': pptx.enum.base.EnumValue(16),
  'MIXED': pptx.enum.base.EnumValue(-2),
  'OLE_CONTROL_OBJECT': pptx.enum.base.EnumValue(12),
  'PICTURE': pptx.enum.base.EnumValue(13),
  'PLACEHOLDER': pptx.enum.base.EnumValue(14),
  'SCRIPT_ANCHOR': pptx.enum.base.EnumValue(18),
  'TABLE': pptx.enum.base.EnumValue(19),
  'TEXT_BOX': pptx.enum.base.EnumValue(17),
  'TEXT_EFFECT': pptx.enum.base.EnumValue(15),
  'WEB_VIDEO': pptx.enum.base.EnumValue(26),
  'validate': <bound method EnumerationBase.validate of <class 'pptx.enum.shapes.MSO_SHAPE_TYPE'>>
}
In [ ]:
dirs(pptx.enum.shapes.PP_MEDIA_TYPE)
Out[ ]:
{
  'MIXED': pptx.enum.base.EnumValue(-2),
  'MOVIE': pptx.enum.base.EnumValue(3),
  'OTHER': pptx.enum.base.EnumValue(1),
  'SOUND': pptx.enum.base.EnumValue(1),
  'validate': <bound method EnumerationBase.validate of <class 'pptx.enum.shapes.PP_MEDIA_TYPE'>>
}
In [ ]:
dir(prs.slides[-1].shapes[1].click_action)
Out[ ]:
[
  '__class__',
  '__delattr__',
  '__dict__',
  '__dir__',
  '__doc__',
  '__eq__',
  '__format__',
  '__ge__',
  '__getattribute__',
  '__gt__',
  '__hash__',
  '__init__',
  '__init_subclass__',
  '__le__',
  '__lt__',
  '__module__',
  '__ne__',
  '__new__',
  '__reduce__',
  '__reduce_ex__',
  '__repr__',
  '__setattr__',
  '__sizeof__',
  '__str__',
  '__subclasshook__',
  '__weakref__',
  '_clear_click_action',
  '_element',
  '_hlink',
  '_hover',
  '_parent',
  '_slide',
  '_slide_index',
  '_slides',
  'action',
  'hyperlink',
  'part',
  'target_slide'
]
In [ ]:
dir(prs.slides[-1].shapes)
Out[ ]:
[
  '__class__',
  '__delattr__',
  '__dict__',
  '__dir__',
  '__doc__',
  '__eq__',
  '__format__',
  '__ge__',
  '__getattribute__',
  '__getitem__',
  '__gt__',
  '__hash__',
  '__init__',
  '__init_subclass__',
  '__iter__',
  '__le__',
  '__len__',
  '__lt__',
  '__module__',
  '__ne__',
  '__new__',
  '__reduce__',
  '__reduce_ex__',
  '__repr__',
  '__setattr__',
  '__sizeof__',
  '__slots__',
  '__str__',
  '__subclasshook__',
  '__weakref__',
  '_add_chart_graphicFrame',
  '_add_cxnSp',
  '_add_graphicFrame_containing_table',
  '_add_pic_from_image_part',
  '_add_sp',
  '_add_textbox_sp',
  '_add_video_timing',
  '_cached_max_shape_id',
  '_element',
  '_grpSp',
  '_is_member_elm',
  '_iter_member_elms',
  '_next_ph_name',
  '_next_shape_id',
  '_parent',
  '_recalculate_extents',
  '_shape_factory',
  '_spTree',
  'add_chart',
  'add_connector',
  'add_group_shape',
  'add_movie',
  'add_picture',
  'add_shape',
  'add_table',
  'add_textbox',
  'build_freeform',
  'clone_layout_placeholders',
  'clone_placeholder',
  'element',
  'index',
  'parent',
  'part',
  'ph_basename',
  'placeholders',
  'title',
  'turbo_add_enabled'
]
In [ ]: